/**   
 * 项目名：五位一体化工安全信息平台
 * 日期：    2019-11-27 02:38:44  
 * Copyright (c) 2015- joysuch-版权所有     
 */

package com.joysuch.wwyt.bp.service.impl;

import com.joysuch.wwyt.bp.bean.BpDeviceFacilityListBean;
import com.joysuch.wwyt.bp.bean.BpDeviceFacilityListSearchBean;
import com.joysuch.wwyt.bp.entity.BpDeviceFacilityCollection;
import com.joysuch.wwyt.bp.entity.BpDeviceFacilityMonitoringPoint;
import com.joysuch.wwyt.bp.entity.dsl.QBpDeviceFacilityCollection;
import com.joysuch.wwyt.bp.entity.dsl.QBpDeviceFacilityMonitoringPoint;
import com.joysuch.wwyt.bp.enums.DeviceFacilityTypes;
import com.joysuch.wwyt.bp.repository.BpDeviceFacilityCollectionDao;
import com.joysuch.wwyt.bp.repository.BpDeviceFacilityMonitoringPointDao;
import com.joysuch.wwyt.bp.service.BpDeviceFacilityCollectionService;
import com.joysuch.wwyt.core.common.util.PageDataUtils;
import com.joysuch.wwyt.core.common.util.PageDataUtils.PageDataConvert;
import com.joysuch.wwyt.mh.bean.MhMonitoringPointBean;
import com.joysuch.wwyt.mh.entity.MhMonitoringPoint;
import com.joysuch.wwyt.mh.entity.dsl.QMhMonitoringPoint;
import com.joysuch.wwyt.risk.repository.RiskDistrictDao;
import com.querydsl.core.Tuple;
import com.querydsl.core.types.ExpressionUtils;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.apache.shiro.util.Assert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

@Service
@Transactional
public class BpDeviceFacilityCollectionServiceImpl implements BpDeviceFacilityCollectionService {

    @Autowired
    private BpDeviceFacilityCollectionDao dao;
    @Autowired
    private RiskDistrictDao riskDistrictDao;
    @Autowired
    private BpDeviceFacilityMonitoringPointDao deviceMonitoringPointDao;
    @Autowired
    private JPAQueryFactory jpaQueryFactory;

    @Override
    public void add(BpDeviceFacilityCollection entity) throws Exception {
        dao.save(entity);
    }

    @Override
    public void update(BpDeviceFacilityCollection entity) throws Exception {
        BpDeviceFacilityCollection content = dao.findById(entity.getId()).get();
        if (content != null) {
            // TODO set nessessary properties
            dao.save(content);
        }
    }

    @Override
    public Page<BpDeviceFacilityCollection> findByPage(Pageable page) {
        return dao.findAll(page);
    }

    @Override
    public void delete(Long id) {
        dao.deleteById(id);
        deviceMonitoringPointDao.deleteByDeviceId(id);
    }

    @Override
    public BpDeviceFacilityCollection findById(Long id) {
        return dao.findById(id).get();
    }

    @Override
    public Page<BpDeviceFacilityListBean> findByPage(Pageable page, BpDeviceFacilityListSearchBean search) {
        QBpDeviceFacilityCollection point = QBpDeviceFacilityCollection.bpDeviceFacilityCollection;
        Predicate predicate = null;
        if (search.getDistrictId() != null) {
            BooleanExpression eq = point.districtId.eq(search.getDistrictId());
            predicate = predicate == null ? eq : ExpressionUtils.and(predicate, eq);
        }
        if (search.getDeviceTypeId() != null) {
            BooleanExpression eq = point.deviceTypeId.eq(search.getDeviceTypeId());
            predicate = predicate == null ? eq : ExpressionUtils.and(predicate, eq);
        }
        if (search.getFacilityType() != null) {
            BooleanExpression eq = point.subType.eq(search.getFacilityType());
            predicate = predicate == null ? eq : ExpressionUtils.and(predicate, eq);
        }
        if (search.getDeviceTypeName() != null) {
            BooleanExpression eq = point.deviceTypeName.like("%" + search.getDeviceTypeName()+ "%");
            predicate = predicate == null ? eq : ExpressionUtils.and(predicate, eq);
        }

        predicate = search.getCodeName() == null ? predicate
                : ExpressionUtils.and(predicate, ExpressionUtils.or(point.name.like("%" + search.getCodeName() + "%"),
                        point.code.like("%" + search.getCodeName() + "%")));

        Page<BpDeviceFacilityCollection> all = predicate == null ? dao.findAll(page) : dao.findAll(predicate, page);
        return PageDataUtils.convertPageData(all,
                new PageDataConvert<BpDeviceFacilityListBean, BpDeviceFacilityCollection>() {
                    @Override
                    public BpDeviceFacilityListBean convert(BpDeviceFacilityCollection f) {
                        BpDeviceFacilityListBean b = new BpDeviceFacilityListBean();
                        b.setId(f.getId());
                        b.setCode(f.getCode());
                        b.setDeviceTypeName(f.getDeviceTypeName());
                        b.setDistrictId(f.getDistrictId());
                        b.setDistrictName(f.getDistrictName());
                        b.setName(f.getName());
                        b.setSubDeviceTypeName(f.getSubType());
                        return b;
                    }
                });
    }

    @Override
    public BpDeviceFacilityCollection addOrUpdateProductionFacility(Long deviceId, String code, String name,
            String subType, Long districtId, Long majorHazardId, String coordinates, String keyEquipment) {
        return addOrUpdateDevice(DeviceFacilityTypes.SHENG_CHAN_ZHUANG_ZHI, deviceId, code, name, subType, districtId,
                majorHazardId, coordinates, keyEquipment);
    }

    @Override
    public BpDeviceFacilityCollection addOrUpdateOtherDevice(DeviceFacilityTypes type, Long deviceId, String code,
            String name, Long districtId, Long majorHazardId, String coordinates) {
        return addOrUpdateDevice(type, deviceId, code, name, null, districtId, majorHazardId, coordinates, null);
    }

    @Override
    public BpDeviceFacilityCollection addOrUpdateDevice(DeviceFacilityTypes type, Long deviceId, String code,
            String name, String subType, Long districtId, Long majorHazardId, String coordinates, String keyEquipment) {
        Assert.notNull(type, "设备类型不能为null");
        BpDeviceFacilityCollection device = dao.findFirstByDeviceTypeNameAndDeviceId(type.getName(), deviceId);
        if (device == null) {
            device = new BpDeviceFacilityCollection();
        }
        device.setCode(code);
        device.setCoordinates(coordinates);
        device.setDeviceId(deviceId);
        device.setDeviceTypeName(type.getName());
        device.setDeviceTypeId(type.getId());
        if (districtId != null) {
            device.setDistrictId(districtId);
            device.setDistrictName(riskDistrictDao.findNameById(districtId));
        }
        device.setMajorHazardId(majorHazardId);
        device.setKeyEquipment(keyEquipment);
        device.setName(name);
        device.setSubType(subType);
        dao.save(device);
        return device;
    }

    @Override
    public void bindDeviceAndMonitorPoints(BpDeviceFacilityCollection device, List<MhMonitoringPoint> points) {
        for (MhMonitoringPoint mh : points) {
            Assert.notNull(mh.getId(), "只能绑定已存在的监测点");
        }
        device.getMhMonitoringPoints().clear();
        device.getMhMonitoringPoints().addAll(points);
        dao.save(device);
    }

    @Override
    public void bindDeviceAndMonitorPointsByIds(BpDeviceFacilityCollection device, List<Long> pointIds) {
        // device.getMhMonitoringPoints().clear();
        // dao.save(device);
        deviceMonitoringPointDao.deleteByDeviceId(device.getId());
        if (pointIds == null || pointIds.isEmpty()) {
            return;
        }
        for (Long id : pointIds) {
            BpDeviceFacilityMonitoringPoint mp = new BpDeviceFacilityMonitoringPoint();
            mp.setDeviceId(device.getId());
            mp.setMonitoringPointId(id);
            deviceMonitoringPointDao.save(mp);
            // MhMonitoringPoint point = mhMonitoringPointDao.getOne(id);
            // device.getMhMonitoringPoints().add(point);
        }
    }

    @Override
    public void bindDeviceAndMonitorPointss(BpDeviceFacilityCollection device, List<MhMonitoringPointBean> pointIds) {
        // device.getMhMonitoringPoints().clear();
        // dao.save(device);

        deviceMonitoringPointDao.deleteByDeviceId(device.getId());
        if (pointIds == null || pointIds.isEmpty()) {
            return;
        }
        for (MhMonitoringPointBean id : pointIds) {
            BpDeviceFacilityMonitoringPoint mp = new BpDeviceFacilityMonitoringPoint();
            mp.setDeviceId(device.getId());
            mp.setMonitoringPointId(id.getId());
            deviceMonitoringPointDao.save(mp);
            // MhMonitoringPoint point = mhMonitoringPointDao.getOne(id);
            // device.getMhMonitoringPoints().add(point);
        }
    }

    @Override
    public List<BpDeviceFacilityCollection> findAll() {
        return dao.findAll();
    }

    @Override
    public void delteByDeviceTypeAndDeviceId(DeviceFacilityTypes type, Long id) {
        // dao.deleteByDeviceTypeNameAndDeviceId(type.getName(), id);
        BpDeviceFacilityCollection device = dao.findFirstByDeviceTypeNameAndDeviceId(type.getName(), id);
        if (device != null) {
            // 删除绑定的监测点
            dao.delete(device);
            deviceMonitoringPointDao.deleteByDeviceId(device.getId());
        }
    }

    @Override
    public BpDeviceFacilityCollection findMonitoryPointBindedDevice(Long monitorPointId) {
        BpDeviceFacilityMonitoringPoint point = deviceMonitoringPointDao.findFirstByMonitoringPointId(monitorPointId);
        return point == null ? null : dao.findById(point.getDeviceId()).orElse(null);
    }

    @Override
    public void bindMonitorPoint(DeviceFacilityTypes type, Long id, Long monitorPointId) {
        BpDeviceFacilityCollection device = dao.findFirstByDeviceTypeNameAndDeviceId(type.getName(), id);
        if (device != null) {
            BpDeviceFacilityMonitoringPoint mp = new BpDeviceFacilityMonitoringPoint();
            mp.setDeviceId(device.getId());
            mp.setMonitoringPointId(monitorPointId);
            deviceMonitoringPointDao.save(mp);
        }
    }

    @Override
    public void unbindMonitorPoint(DeviceFacilityTypes type, Long id, Long monitorPointId) {
        BpDeviceFacilityCollection device = dao.findFirstByDeviceTypeNameAndDeviceId(type.getName(), id);
        if (device != null) {
            deviceMonitoringPointDao.deleteByDeviceIdAndMonitoringPointId(device.getId(), monitorPointId);
        }
    }

    @Override
    public List<String> findDeviceBindedMonitorPointCodes(DeviceFacilityTypes type, Long id) {
        BpDeviceFacilityCollection device = dao.findFirstByDeviceTypeNameAndDeviceId(type.getName(), id);
        if (device != null) {
            return deviceMonitoringPointDao.getMonitoringPointCodesByDeviceId(device.getId());
        }
        return Collections.EMPTY_LIST;
    }

    @Override
    public List<List<String>> findDeviceBindedMonitorPointCodes(DeviceFacilityTypes type, List<Long> ids) {
        if(ids == null || ids.isEmpty()) {
            return Collections.EMPTY_LIST;
        }
        QBpDeviceFacilityCollection facility = QBpDeviceFacilityCollection.bpDeviceFacilityCollection;
        QBpDeviceFacilityMonitoringPoint fp = QBpDeviceFacilityMonitoringPoint.bpDeviceFacilityMonitoringPoint;
        QMhMonitoringPoint point = QMhMonitoringPoint.mhMonitoringPoint;
        List<Tuple> fetch = jpaQueryFactory.select(facility.deviceId, point.pointCode).from(facility, fp, point).where(facility.deviceTypeName.eq(type.getName()),
                facility.deviceId.in(ids), facility.id.eq(fp.deviceId), fp.monitoringPointId.eq(point.id)).fetch();
        List<List<String>> re = new ArrayList<>(ids.size());
        for(int i=0;i<ids.size();i++) {
            Long deviceId = ids.get(i);
            List<String> list = new ArrayList<>();
            for(Tuple t : fetch) {
                if(Objects.equals(t.get(facility.deviceId), deviceId)) {
                    list.add(t.get(point.pointCode));
                }
            }
            re.add(list);
        }
        return re;
    }

}
